﻿using Microsoft.Extensions.Options;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using wx.web.Models;

namespace wx.web.Interface
{
    public class WeChatService : IWeChatService
    {
        private readonly WeChatSettings _settings;
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly ILogger<WeChatService> _logger;

        public WeChatService(IOptions<WeChatSettings> settings,
                            IHttpClientFactory httpClientFactory,
                            ILogger<WeChatService> logger)
        {
            _settings = settings.Value;
            _httpClientFactory = httpClientFactory;
            _logger = logger;
        }

        /// <summary>
        /// 生成微信授权URL
        /// </summary>
        public string GenerateAuthorizationUrl(string redirectUrl, string scope = "snsapi_base", string state = "")
        {
            if (string.IsNullOrEmpty(state))
                state = Guid.NewGuid().ToString("N");

            var encodedRedirectUrl = Uri.EscapeDataString(redirectUrl);

            return $"https://open.weixin.qq.com/connect/oauth2/authorize?" +
                   $"appid={_settings.AppId}&" +
                   $"redirect_uri={encodedRedirectUrl}&" +
                   $"response_type=code&" +
                   $"scope={scope}&" +
                   $"state={state}#wechat_redirect";
        }

        /// <summary>
        /// 使用code获取access_token
        /// </summary>
        public async Task<WeChatApiResponse> GetAccessTokenAsync(string code)
        {
            try
            {
                var client = _httpClientFactory.CreateClient();
                var url = $"https://api.weixin.qq.com/sns/oauth2/access_token?" +
                          $"appid={_settings.AppId}&" +
                          $"secret={_settings.AppSecret}&" +
                          $"code={code}&" +
                          $"grant_type=authorization_code";

                var response = await client.GetAsync(url);
                var content = await response.Content.ReadAsStringAsync();

                _logger.LogInformation($"微信AccessToken响应: {content}");

                var result = JsonSerializer.Deserialize<WeChatApiResponse>(content);

                if (result?.ErrorCode != 0)
                {
                    _logger.LogError($"微信授权失败: {result?.ErrorCode} - {result?.ErrorMessage}");
                    throw new Exception($"微信授权失败: {result?.ErrorMessage}");
                }

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取微信AccessToken失败");
                throw;
            }
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        public async Task<WeChatUserInfo> GetUserInfoAsync(string accessToken, string openId)
        {
            try
            {
                var client = _httpClientFactory.CreateClient();
                var url = $"https://api.weixin.qq.com/sns/userinfo?" +
                          $"access_token={accessToken}&" +
                          $"openid={openId}&" +
                          $"lang=zh_CN";

                var response = await client.GetAsync(url);
                var content = await response.Content.ReadAsStringAsync();

                _logger.LogInformation($"微信用户信息响应: {content}");

                var result = JsonSerializer.Deserialize<WeChatUserInfo>(content);

                if (result?.ErrorCode != 0)
                {
                    _logger.LogError($"获取用户信息失败: {result?.ErrorCode} - {result?.ErrorMessage}");
                    throw new Exception($"获取用户信息失败: {result?.ErrorMessage}");
                }

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取微信用户信息失败");
                throw;
            }
        }

        /// <summary>
        /// 验证微信签名
        /// </summary>
        public bool ValidateSignature(string signature, string timestamp, string nonce)
        {
            var arr = new[] { _settings.Token, timestamp, nonce }.OrderBy(x => x).ToArray();
            var rawString = string.Join("", arr);

            using var sha1 = SHA1.Create();
            var bytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(rawString));
            var computedSignature = BitConverter.ToString(bytes).Replace("-", "").ToLower();

            return computedSignature == signature.ToLower();
        }
    }
}
